package com.summli.basic.class08;

import java.util.LinkedList;

/**
 * 给定一棵二叉树的头节点head，返回这颗二叉树中是不是完全二叉树
 *
 * 二叉树递归套路：
 * 完全二叉树要不就是满的，要不就是在向满的过程变化
 *
 * 1、左边满右边满，并且高度相等
 * 2、左边不满，但是是完全二叉树，右边必须满的，并且左边的高度=右边的高度+1、
 * 3、左边满的右边慢的，left.height = right.height+1
 * 4、左边满的右边不满但是是完全二叉树，left.height = right.height
 *
 */
public class Code06_IsCBT {
    public static class Node {
        public int value;
        public Node left;
        public Node right;

        public Node(int data) {
            this.value = data;
        }
    }
    public static class Info{
        public boolean isFull;
        public boolean isCBT;
        public int height;

        public Info(boolean isFull, boolean isCBT, int height) {
            this.isFull = isFull;
            this.isCBT = isCBT;
            this.height = height;
        }
    }
    public static boolean isCBT2(Node head) {
        if(head == null){
            return true;
        }
        return process(head).isCBT;
    }

    private static Info process(Node cur) {
        if(cur == null){
            return new Info(true,true,0);
        }
        Info leftInfo = process(cur.left);
        Info rightInfo = process(cur.right);
        int height = Math.max(leftInfo.height,rightInfo.height)+1;
        boolean isFull = leftInfo.isFull && rightInfo.isFull && (leftInfo.height == rightInfo.height);
        boolean isCBT = false;
        if(isFull){
            isCBT = true;
        }else{
            // others
            if(leftInfo.isCBT && rightInfo.isFull && (leftInfo.height == rightInfo.height+1)){
                isCBT = true;
            }
            if(leftInfo.isFull && rightInfo.isFull && (leftInfo.height == rightInfo.height+1)){
                isCBT = true;
            }
            if(leftInfo.isFull && rightInfo.isCBT && (leftInfo.height == rightInfo.height)){
                isCBT = true;
            }
        }
        return new Info(isFull,isCBT,height);
    }

    public static void main(String[] args) {
        int maxLevel = 5;
        int maxValue = 100;
        int testTimes = 1000000;
        for (int i = 0; i < testTimes; i++) {
            Node head = generateRandomBST(maxLevel,maxValue);
            if (isCBT1(head) != isCBT2(head)) {
                System.out.println("Oops!");
            }
        }
        System.out.println("finish");
    }
    // ==== test
    private static Node generateRandomBST(int maxLevel, int maxValue) {
        return generate(1,maxLevel,maxValue);
    }

    private static Node generate(int level, int maxLevel, int maxValue) {
        if(level > maxLevel || Math.random() < 0.5){
            return null;
        }
        Node head = new Node((int)Math.random()*maxValue);
        head.left = generate(level+1, maxLevel, maxValue);
        head.right = generate(level+1, maxLevel, maxValue);
        return head;
    }

    public static boolean isCBT1(Node head) {
        if (head == null) {
            return true;
        }
        LinkedList<Node> queue = new LinkedList<>();
        // 是否遇到过左右两个孩子不双全的节点
        boolean leaf = false;
        Node l = null;
        Node r = null;
        queue.add(head);
        while (!queue.isEmpty()) {
            head = queue.poll();
            l = head.left;
            r = head.right;
            if (
                // 如果遇到了不双全的节点之后，又发现当前节点不是叶节点
                    (leaf && !(l == null && r == null)) || (l == null && r != null)) {
                return false;
            }
            if (l != null) {
                queue.add(l);
            }
            if (r != null) {
                queue.add(r);
            }
            if (l == null || r == null) {
                leaf = true;
            }
        }
        return true;
    }
}
